#include <linux/backing-dev.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/freezer.h>
#include <linux/sched/signal.h>
#include <linux/slab_def.h>
#include <linux/random.h>

#include "dbcache.h"
#include "db.h"
#include "hc.h"
#include "kmeans.h"
#include "util_db.h"

bool get_bio_flag(struct bio *bio, unsigned int FLAG)
{
    return (bio->bi_opf & FLAG) != 0;
}

__u32 hotness_get(struct cached_dev *dc, struct bio *bio) {
    unsigned int ext_start;
    unsigned int ext_end;
    unsigned int ext_index;
    unsigned int ext_count;
    __u64 hotness_sum = 0;

    hotness_ext(bio, &ext_start, &ext_end);
    // printk("%s: hotness_ext = [%u, %u].\n", __func__, ext_start, ext_end);

    for (ext_index = ext_start; ext_index <= ext_end; ext_index++) {
        hotness_sum += dc->hc->hotness_array[ext_index];
        ext_count++;
    }

    if(ext_count) {
        return hotness_sum / ext_count;
    } else {
        printk("%s: error! ext_count cannot be 0!\n", __func__);
        return 0;
    }
}

void hotness_update(struct cached_dev *dc, struct bio *bio) {
    unsigned int ext_start;
    unsigned int ext_index;
    unsigned int ext_end;

    hotness_ext(bio, &ext_start, &ext_end);
    // printk("%s: hotness_ext = [%u, %u].\n", __func__, ext_start, ext_end);

    for (ext_index = ext_start; ext_index <= ext_end; ext_index++) {
        if (dc->hc->hotness_array[ext_index] == hotness_max - 1)
            continue;
        dc->hc->hotness_array[ext_index]++;
    }
}

unsigned int hotness_get_type(struct cached_dev *dc, struct bio *bio) {
    __u32 hotness = hotness_get(dc, bio);
    unsigned int type = kmeans_type(dc, hotness);
    return type;
}

void hotness_reset(struct cached_dev *dc, struct bio *bio) {
    unsigned int ext_start;
    unsigned int ext_index;
    unsigned int ext_end;

    hotness_ext(bio, &ext_start, &ext_end);
    // printk("%s: hotness_ext = [%u, %u].\n", __func__, ext_start, ext_end);

    for (ext_index = ext_start; ext_index <= ext_end; ext_index++) {
        dc->hc->hotness_array[ext_index] = 0;
    }
}
